home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / TEMP / GNU / bison / MfcalcSymu < prev    next >
Text File  |  1995-06-28  |  6KB  |  220 lines

  1. Mfcalc Symtab
  2. Previous: <Mfcalc Rules=>MfcalcRulf> * Next: <Exercises=>Exercises> * Up: <Multi-function Calc=>Multifunct>
  3.  
  4. #Wrap on
  5. {fH4}The {fCode}mfcalc{f} Symbol Table{f}
  6.  
  7. The multi-function calculator requires a symbol table to keep track of the
  8. names and meanings of variables and functions.  This doesn't affect the
  9. grammar rules (except for the actions) or the Bison declarations, but it
  10. requires some additional C functions for support.
  11.  
  12. The symbol table itself consists of a linked list of records.  Its
  13. definition, which is kept in the header {fCite}calc.h{f}, is as follows.  It
  14. provides for either functions or variables to be placed in the table.
  15.  
  16. #Wrap off
  17. #fCode
  18. \/\* Data type for links in the chain of symbols.      \*\/
  19. struct symrec
  20. \{
  21.   char \*name;  \/\* name of symbol                     \*\/
  22.   int type;    \/\* type of symbol: either VAR or FNCT \*\/
  23.   union \{
  24.     double var;           \/\* value of a VAR          \*\/
  25.     double (\*fnctptr)();  \/\* value of a FNCT         \*\/
  26.   \} value;
  27.   struct symrec \*next;    \/\* link field              \*\/
  28. \};
  29.  
  30. typedef struct symrec symrec;
  31.  
  32. \/\* The symbol table: a chain of `struct symrec'.     \*\/
  33. extern symrec \*sym\_table;
  34.  
  35. symrec \*putsym ();
  36. symrec \*getsym ();
  37. #f
  38. #Wrap on
  39.  
  40. The new version of {fCode}main{f} includes a call to {fCode}init\_table{f}, a
  41. function that initializes the symbol table.  Here it is, and
  42. {fCode}init\_table{f} as well:
  43.  
  44. #Wrap off
  45. #fCode
  46. \#include <stdio.h>
  47.  
  48. main ()
  49. \{
  50.   init\_table ();
  51.   yyparse ();
  52. \}
  53.  
  54. yyerror (s)  \/\* Called by yyparse on error \*\/
  55.      char \*s;
  56. \{
  57.   printf ("%s\\n", s);
  58. \}
  59.  
  60. struct init
  61. \{
  62.   char \*fname;
  63.   double (\*fnct)();
  64. \};
  65.  
  66. struct init arith\_fncts[]
  67.   = \{
  68.       "sin", sin,
  69.       "cos", cos,
  70.       "atan", atan,
  71.       "ln", log,
  72.       "exp", exp,
  73.       "sqrt", sqrt,
  74.       0, 0
  75.     \};
  76.  
  77. \/\* The symbol table: a chain of `struct symrec'.  \*\/
  78. symrec \*sym\_table = (symrec \*)0;
  79.  
  80. init\_table ()  \/\* puts arithmetic functions in table. \*\/
  81. \{
  82.   int i;
  83.   symrec \*ptr;
  84.   for (i = 0; arith\_fncts[i].fname != 0; i++)
  85.     \{
  86.       ptr = putsym (arith\_fncts[i].fname, FNCT);
  87.       ptr->value.fnctptr = arith\_fncts[i].fnct;
  88.     \}
  89. \}
  90. #f
  91. #Wrap on
  92.  
  93. By simply editing the initialization list and adding the necessary include
  94. files, you can add additional functions to the calculator.
  95.  
  96. Two important functions allow look-up and installation of symbols in the
  97. symbol table.  The function {fCode}putsym{f} is passed a name and the type
  98. ({fCode}VAR{f} or {fCode}FNCT{f}) of the object to be installed.  The object is
  99. linked to the front of the list, and a pointer to the object is returned.
  100. The function {fCode}getsym{f} is passed the name of the symbol to look up.  If
  101. found, a pointer to that symbol is returned; otherwise zero is returned.
  102.  
  103. #Wrap off
  104. #fCode
  105. symrec \*
  106. putsym (sym\_name,sym\_type)
  107.      char \*sym\_name;
  108.      int sym\_type;
  109. \{
  110.   symrec \*ptr;
  111.   ptr = (symrec \*) malloc (sizeof (symrec));
  112.   ptr->name = (char \*) malloc (strlen (sym\_name) + 1);
  113.   strcpy (ptr->name,sym\_name);
  114.   ptr->type = sym\_type;
  115.   ptr->value.var = 0; \/\* set value to 0 even if fctn.  \*\/
  116.   ptr->next = (struct symrec \*)sym\_table;
  117.   sym\_table = ptr;
  118.   return ptr;
  119. \}
  120.  
  121. symrec \*
  122. getsym (sym\_name)
  123.      char \*sym\_name;
  124. \{
  125.   symrec \*ptr;
  126.   for (ptr = sym\_table; ptr != (symrec \*) 0;
  127.        ptr = (symrec \*)ptr->next)
  128.     if (strcmp (ptr->name,sym\_name) == 0)
  129.       return ptr;
  130.   return 0;
  131. \}
  132. #f
  133. #Wrap on
  134.  
  135. The function {fCode}yylex{f} must now recognize variables, numeric values, and
  136. the single-character arithmetic operators.  Strings of alphanumeric
  137. characters with a leading nondigit are recognized as either variables or
  138. functions depending on what the symbol table says about them.
  139.  
  140. The string is passed to {fCode}getsym{f} for look up in the symbol table.  If
  141. the name appears in the table, a pointer to its location and its type
  142. ({fCode}VAR{f} or {fCode}FNCT{f}) is returned to {fCode}yyparse{f}.  If it is not
  143. already in the table, then it is installed as a {fCode}VAR{f} using
  144. {fCode}putsym{f}.  Again, a pointer and its type (which must be {fCode}VAR{f}) is
  145. returned to {fCode}yyparse{f}.
  146.  
  147. No change is needed in the handling of numeric values and arithmetic
  148. operators in {fCode}yylex{f}.
  149.  
  150. #Wrap off
  151. #fCode
  152. \#include <ctype.h>
  153. yylex ()
  154. \{
  155.   int c;
  156.  
  157.   \/\* Ignore whitespace, get first nonwhite character.  \*\/
  158.   while ((c = getchar ()) == ' ' || c == '\\t');
  159.  
  160.   if (c == EOF)
  161.     return 0;
  162.  
  163.   \/\* Char starts a number => parse the number.         \*\/
  164.   if (c == '.' || isdigit (c))
  165.     \{
  166.       ungetc (c, stdin);
  167.       scanf ("%lf", &yylval.val);
  168.       return NUM;
  169.     \}
  170.  
  171.   \/\* Char starts an identifier => read the name.       \*\/
  172.   if (isalpha (c))
  173.     \{
  174.       symrec \*s;
  175.       static char \*symbuf = 0;
  176.       static int length = 0;
  177.       int i;
  178.  
  179.       \/\* Initially make the buffer long enough
  180.          for a 40-character symbol name.  \*\/
  181.       if (length == 0)
  182.         length = 40, symbuf = (char \*)malloc (length + 1);
  183.  
  184.       i = 0;
  185.       do
  186.         \{
  187.           \/\* If buffer is full, make it bigger.        \*\/
  188.           if (i == length)
  189.             \{
  190.               length \*= 2;
  191.               symbuf = (char \*)realloc (symbuf, length + 1);
  192.             \}
  193.           \/\* Add this character to the buffer.         \*\/
  194.           symbuf[i++] = c;
  195.           \/\* Get another character.                    \*\/
  196.           c = getchar ();
  197.         \}
  198.       while (c != EOF && isalnum (c));
  199.  
  200.       ungetc (c, stdin);
  201.       symbuf[i] = '\\0';
  202.  
  203.       s = getsym (symbuf);
  204.       if (s == 0)
  205.         s = putsym (symbuf, VAR);
  206.       yylval.tptr = s;
  207.       return s->type;
  208.     \}
  209.  
  210.   \/\* Any other character is a token by itself.        \*\/
  211.   return c;
  212. \}
  213. #f
  214. #Wrap on
  215.  
  216. This program is both powerful and flexible. You may easily add new
  217. functions, and it is a simple job to modify this code to install predefined
  218. variables such as {fCode}pi{f} or {fCode}e{f} as well.
  219.  
  220.